www.gusucode.com > 基于Visual C++高级界面特效制作百例源码程序 > 基于Visual C++高级界面特效制作百例源码程序/code/char24/docking_window/sizecbar.cpp
///////////////////////////////////////////////////////////////////////// // Copyright (C) 1998 by Cristi Posea // All rights reserved // // Distribute freely, except: don't remove my name from the source or // documentation (don't take credit for my work), mark your changes // (don't get me blamed for your possible bugs), don't alter or remove // this notice. // No warrantee of any kind, express or implied, is included with this // software; use at your own risk, responsibility for damages (if any) to // anyone resulting from the use of this software rests entirely with the // user. // // Send bug reports, bug fixes, enhancements, requests, flames, etc., // and I'll try to keep a version up to date. I can be reached at: // cristi@gds.ro ///////////////////////////////////////////////////////////////////////// // // Acknowledgements: // o Thanks to Harlan R. Seymour (harlan@hcube.com) for motivating me // to update this code. Also he prompted me to a bug durring // the developement phase. // o Thanks to Zafir Anjum (zafir@codeguru.com) for publishing this // code on his cool site (www.codeguru.com). // o Some ideeas for the gripper came from the CToolBarEx flat toolbar // by Joerg Koenig (Joerg.Koenig@rhein-neckar.de). Also he inspired // me on writting this notice:) . Thanks, Joerg! // o Thanks to Jakawan Ratiwanich (jack@alpha.fsec.ucf.edu) and to // Udo Schaefer(Udo.Schaefer@vcase.de) for the dwStyle bug fix under // VC++ 6.0. // o Thanks to Microsoft developers for the MFC source code. After // all, most of this class code came from there. // ///////////////////////////////////////////////////////////////////////// // // Usage: // o Derive your class from CSizingControlBar. Then create your child // controls/windows on it. // o Include your class header in Mainfrm.cpp and add a member // variable to CMainFrame. In CMainFrame::OnCreate(), create the // control bar, enable it to dock, and so on... like a toolbar or // any control bar. // o More details at // http://www.codeguru.com/docking/docking_window.shtml or search // http://www.codeguru.com for my name if the article has moved. // ///////////////////////////////////////////////////////////////////////// // SizingControlBar.cpp : implementation file // #include "stdafx.h" #include "afxpriv.h" // for CDockContext #include "sizecbar.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////// // CSizingControlBar CSizingControlBar::CSizingControlBar() { m_sizeMin = CSize(32, 32); m_sizeHorz = CSize(200, 200); m_sizeVert = CSize(200, 200); m_sizeFloat = CSize(200, 200); m_bTracking = FALSE; m_bInRecalcNC = FALSE; m_cxEdge = 5; m_bDragShowContent = FALSE; } CSizingControlBar::~CSizingControlBar() { } BEGIN_MESSAGE_MAP(CSizingControlBar, CControlBar) //{{AFX_MSG_MAP(CSizingControlBar) ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() ON_WM_SETCURSOR() ON_WM_WINDOWPOSCHANGED() ON_WM_NCPAINT() ON_WM_NCLBUTTONDOWN() ON_WM_NCHITTEST() ON_WM_NCCALCSIZE() ON_WM_LBUTTONDOWN() ON_WM_CAPTURECHANGED() ON_WM_LBUTTONDBLCLK() ON_WM_PAINT() ON_WM_SIZE() ON_WM_RBUTTONDOWN() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////// // CSizingControlBar message handlers BOOL CSizingControlBar::Create(LPCTSTR lpszWindowName, CWnd* pParentWnd, CSize sizeDefault, BOOL bHasGripper, UINT nID, DWORD dwStyle) { ASSERT_VALID(pParentWnd); // must have a parent ASSERT (!((dwStyle & CBRS_SIZE_FIXED) && (dwStyle & CBRS_SIZE_DYNAMIC))); // save the style SetBarStyle(dwStyle & CBRS_ALL); CString wndclass = ::AfxRegisterWndClass(CS_DBLCLKS, ::LoadCursor(NULL, IDC_ARROW), ::GetSysColorBrush(COLOR_BTNFACE), 0); dwStyle &= ~CBRS_ALL; dwStyle &= WS_VISIBLE | WS_CHILD; if (!CWnd::Create(wndclass, lpszWindowName, dwStyle, CRect(0,0,0,0), pParentWnd, nID)) return FALSE; m_sizeHorz = sizeDefault; m_sizeVert = sizeDefault; m_sizeFloat = sizeDefault; m_bHasGripper = bHasGripper; m_cyGripper = m_bHasGripper ? 12 : 0; return TRUE; } BOOL CSizingControlBar::IsHorzDocked() const { return (m_nDockBarID == AFX_IDW_DOCKBAR_TOP || m_nDockBarID == AFX_IDW_DOCKBAR_BOTTOM); } BOOL CSizingControlBar::IsVertDocked() const { return (m_nDockBarID == AFX_IDW_DOCKBAR_LEFT || m_nDockBarID == AFX_IDW_DOCKBAR_RIGHT); } CSize CSizingControlBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz) { CRect rc; m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_TOP)->GetWindowRect(rc); int nHorzDockBarWidth = bStretch ? 32767 : rc.Width() + 4; m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_LEFT)->GetWindowRect(rc); int nVertDockBarHeight = bStretch ? 32767 : rc.Height() + 4; if (bHorz) return CSize(nHorzDockBarWidth, m_sizeHorz.cy); else return CSize(m_sizeVert.cx, nVertDockBarHeight); } CSize CSizingControlBar::CalcDynamicLayout(int nLength, DWORD dwMode) { if (dwMode & (LM_HORZDOCK | LM_VERTDOCK)) { if (nLength == -1) GetDockingFrame()->DelayRecalcLayout(); return CControlBar::CalcDynamicLayout(nLength,dwMode); } if (dwMode & LM_MRUWIDTH) return m_sizeFloat; if (dwMode & LM_COMMIT) { m_sizeFloat.cx = nLength; return m_sizeFloat; } if (dwMode & LM_LENGTHY) return CSize(m_sizeFloat.cx, m_sizeFloat.cy = max(m_sizeMin.cy, nLength)); else return CSize(max(m_sizeMin.cx, nLength), m_sizeFloat.cy); } void CSizingControlBar::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos) { CControlBar::OnWindowPosChanged(lpwndpos); // Find on which side are we docked m_nDockBarID = GetParent()->GetDlgCtrlID(); if (!m_bInRecalcNC) { m_bInRecalcNC = TRUE; // Force recalc the non-client area SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED); m_bInRecalcNC = FALSE; } } BOOL CSizingControlBar::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { if ((nHitTest != HTSIZE) || m_bTracking) return CControlBar::OnSetCursor(pWnd, nHitTest, message); if (IsHorzDocked()) ::SetCursor(::LoadCursor(NULL, IDC_SIZENS)); else ::SetCursor(::LoadCursor(NULL, IDC_SIZEWE)); return TRUE; } ///////////////////////////////////////////////////////////////////////// // Mouse Handling // void CSizingControlBar::OnLButtonDown(UINT nFlags, CPoint point) { if (m_pDockBar != NULL) { // start the drag ASSERT(m_pDockContext != NULL); ClientToScreen(&point); m_pDockContext->StartDrag(point); } else CWnd::OnLButtonDown(nFlags, point); } void CSizingControlBar::OnLButtonDblClk(UINT nFlags, CPoint point) { if (m_pDockBar != NULL) { // toggle docking ASSERT(m_pDockContext != NULL); m_pDockContext->ToggleDocking(); } else CWnd::OnLButtonDblClk(nFlags, point); } void CSizingControlBar::OnNcLButtonDown(UINT nHitTest, CPoint point) { if (m_bTracking) return; if ((nHitTest == HTSIZE) && !IsFloating()) StartTracking(); else CControlBar::OnNcLButtonDown(nHitTest, point); } void CSizingControlBar::OnLButtonUp(UINT nFlags, CPoint point) { if (m_bTracking) StopTracking(TRUE); CControlBar::OnLButtonUp(nFlags, point); } void CSizingControlBar::OnRButtonDown(UINT nFlags, CPoint point) { if (m_bTracking) StopTracking(FALSE); CControlBar::OnRButtonDown(nFlags, point); } void CSizingControlBar::OnMouseMove(UINT nFlags, CPoint point) { if (m_bTracking) { ASSERT (!IsFloating()); CPoint pt = point; ClientToScreen(&pt); OnTrackUpdateSize(pt); } CControlBar::OnMouseMove(nFlags, point); } void CSizingControlBar::OnCaptureChanged(CWnd *pWnd) { if (m_bTracking && pWnd != this) StopTracking(FALSE); // cancel tracking CControlBar::OnCaptureChanged(pWnd); } void CSizingControlBar::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp) { // Compute the rectangle of the mobile edge GetWindowRect(m_rectBorder); m_rectBorder.OffsetRect(-m_rectBorder.left, -m_rectBorder.top); m_rectBorder.DeflateRect(1, 1); m_rectGripper = m_rectBorder; m_rectGripper.DeflateRect(5, 5); m_rectGripper.right -= m_cxEdge; m_rectGripper.bottom -= m_cxEdge; CRect rc = lpncsp->rgrc[0]; DWORD dwBorderStyle = m_dwStyle | CBRS_BORDER_ANY; switch(m_nDockBarID) { case AFX_IDW_DOCKBAR_TOP: dwBorderStyle &= ~CBRS_BORDER_BOTTOM; rc.DeflateRect(m_cyGripper + 2, 2, 2, m_cxEdge + 2); m_rectBorder.top = m_rectBorder.bottom - m_cxEdge; break; case AFX_IDW_DOCKBAR_BOTTOM: dwBorderStyle &= ~CBRS_BORDER_TOP; rc.DeflateRect(m_cyGripper + 2, m_cxEdge + 2, 2, 2); m_rectBorder.bottom = m_rectBorder.top + m_cxEdge; m_rectGripper.OffsetRect(0, m_cxEdge); break; case AFX_IDW_DOCKBAR_LEFT: dwBorderStyle &= ~CBRS_BORDER_RIGHT; rc.DeflateRect(2, m_cyGripper + 2, m_cxEdge + 2, 6); m_rectBorder.left = m_rectBorder.right - m_cxEdge; break; case AFX_IDW_DOCKBAR_RIGHT: dwBorderStyle &= ~CBRS_BORDER_LEFT; rc.DeflateRect(m_cxEdge + 2, m_cyGripper + 2, 2, 6); m_rectBorder.right = m_rectBorder.left + m_cxEdge; m_rectGripper.OffsetRect(m_cxEdge, 0); break; default: m_rectBorder.SetRectEmpty(); break; } lpncsp->rgrc[0] = rc; SetBarStyle(dwBorderStyle); } void CSizingControlBar::OnNcPaint() { // get window DC that is clipped to the non-client area CWindowDC dc(this); CRect rectClient; GetClientRect(rectClient); CRect rectWindow; GetWindowRect(rectWindow); ScreenToClient(rectWindow); rectClient.OffsetRect(-rectWindow.left, -rectWindow.top); dc.ExcludeClipRect(rectClient); // draw borders in non-client area rectWindow.OffsetRect(-rectWindow.left, -rectWindow.top); DrawBorders(&dc, rectWindow); // erase parts not drawn dc.IntersectClipRect(rectWindow); // erase NC background the hard way HBRUSH hbr = (HBRUSH)GetClassLong(m_hWnd, GCL_HBRBACKGROUND); ::FillRect(dc.m_hDC, rectWindow, hbr); // paint the mobile edge dc.Draw3dRect(m_rectBorder, ::GetSysColor(COLOR_BTNHIGHLIGHT), ::GetSysColor(COLOR_BTNSHADOW)); if (m_bHasGripper) { // paint the gripper CRect gripper = m_rectGripper; if (IsHorzDocked()) { // gripper at left gripper.right = gripper.left + 3; dc.Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT), ::GetSysColor(COLOR_BTNSHADOW)); gripper.OffsetRect(3, 0); dc.Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT), ::GetSysColor(COLOR_BTNSHADOW)); } else if (IsVertDocked()) { // gripper at top gripper.bottom = gripper.top + 3; dc.Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT), ::GetSysColor(COLOR_BTNSHADOW)); gripper.OffsetRect(0, 3); dc.Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT), ::GetSysColor(COLOR_BTNSHADOW)); } } ReleaseDC(&dc); } void CSizingControlBar::OnPaint() { // overridden to skip border painting based on clientrect CPaintDC dc(this); } UINT CSizingControlBar::OnNcHitTest(CPoint point) { if (IsFloating()) return CControlBar::OnNcHitTest(point); CRect rc; GetWindowRect(rc); point.Offset(-rc.left, -rc.top); if (m_rectBorder.PtInRect(point)) return HTSIZE; else return HTCLIENT; } ///////////////////////////////////////////////////////////////////////// // CSizingControlBar implementation helpers void CSizingControlBar::StartTracking() { SetCapture(); // make sure no updates are pending RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW); m_bDragShowContent = QueryDragFullWindows(); if (!m_bDragShowContent) m_pDockSite->LockWindowUpdate(); m_sizeOld = IsHorzDocked() ? m_sizeHorz : m_sizeVert; CRect rect; GetWindowRect(&rect); m_ptOld = m_rectBorder.CenterPoint() + rect.TopLeft(); m_sizeMax = CalcMaxSize(); m_bTracking = TRUE; if (!m_bDragShowContent) OnTrackInvertTracker(); } void CSizingControlBar::StopTracking(BOOL bAccept) { if (!m_bDragShowContent) { OnTrackInvertTracker(); m_pDockSite->UnlockWindowUpdate(); } m_bTracking = FALSE; ReleaseCapture(); if (!bAccept) // resize canceled? { // restore old size if (IsHorzDocked()) m_sizeHorz = m_sizeOld; else m_sizeVert = m_sizeOld; } m_pDockSite->DelayRecalcLayout(); } void CSizingControlBar::OnTrackUpdateSize(CPoint& point) { BOOL bHorz = IsHorzDocked(); CSize sizeNew = m_sizeOld; if ((m_nDockBarID == AFX_IDW_DOCKBAR_TOP) || (m_nDockBarID == AFX_IDW_DOCKBAR_LEFT)) sizeNew += point - m_ptOld; else sizeNew -= point - m_ptOld; // check limits sizeNew.cx = max(m_sizeMin.cx, sizeNew.cx); sizeNew.cy = max(m_sizeMin.cy, sizeNew.cy); sizeNew.cx = min(m_sizeMax.cx, sizeNew.cx); sizeNew.cy = min(m_sizeMax.cy, sizeNew.cy); if ((sizeNew.cy == m_sizeHorz.cy) && bHorz || (sizeNew.cx == m_sizeVert.cx) && !bHorz) return; // no size change if (!m_bDragShowContent) OnTrackInvertTracker(); if (bHorz) m_sizeHorz = sizeNew; else m_sizeVert = sizeNew; if (!m_bDragShowContent) OnTrackInvertTracker(); else m_pDockSite->DelayRecalcLayout(); } CSize CSizingControlBar::CalcMaxSize() { // the control bar cannot grow with more than the size of // remaining client area of the frame CRect rect; m_pDockSite->GetClientRect(&rect); CSize size = rect.Size(); CWnd* pBar; if (IsHorzDocked()) { if (pBar = m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_TOP)) { pBar->GetWindowRect(&rect); size -= rect.Size(); } if (pBar = m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_BOTTOM)) { pBar->GetWindowRect(&rect); size -= rect.Size(); } if (pBar = m_pDockSite->GetControlBar(AFX_IDW_STATUS_BAR)) { pBar->GetWindowRect(&rect); size -= rect.Size(); } } else { if (pBar = m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_LEFT)) { pBar->GetWindowRect(&rect); size -= rect.Size(); } if (pBar = m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_RIGHT)) { pBar->GetWindowRect(&rect); size -= rect.Size(); } } size -= CSize(4, 4); size += IsHorzDocked() ? m_sizeHorz : m_sizeVert; return size; } void CSizingControlBar::OnTrackInvertTracker() { ASSERT_VALID(this); ASSERT(m_bTracking); CRect rect = m_rectBorder; CRect rectBar, rectFrame; GetWindowRect(rectBar); rect.OffsetRect(rectBar.TopLeft()); m_pDockSite->GetWindowRect(rectFrame); rect.OffsetRect(-rectFrame.left, -rectFrame.top); switch (m_nDockBarID) { case AFX_IDW_DOCKBAR_TOP: rect.OffsetRect(0, m_sizeHorz.cy - m_sizeOld.cy); break; case AFX_IDW_DOCKBAR_BOTTOM: rect.OffsetRect(0, m_sizeOld.cy - m_sizeHorz.cy); break; case AFX_IDW_DOCKBAR_LEFT: rect.OffsetRect(m_sizeVert.cx - m_sizeOld.cx, 0); break; case AFX_IDW_DOCKBAR_RIGHT: rect.OffsetRect(m_sizeOld.cx - m_sizeVert.cx, 0); break; } if (IsVertDocked()) rect.bottom -= 4; rect.DeflateRect(1, 1); CDC *pDC = m_pDockSite->GetDCEx(NULL, DCX_WINDOW|DCX_CACHE|DCX_LOCKWINDOWUPDATE); CBrush* pBrush = CDC::GetHalftoneBrush(); HBRUSH hOldBrush = NULL; if (pBrush != NULL) hOldBrush = (HBRUSH)::SelectObject(pDC->m_hDC, pBrush->m_hObject); pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATINVERT); if (hOldBrush != NULL) ::SelectObject(pDC->m_hDC, hOldBrush); m_pDockSite->ReleaseDC(pDC); } BOOL CSizingControlBar::QueryDragFullWindows() const { TCHAR sDragfullWindows[2]; DWORD cbDragfullWindows = sizeof(DWORD); DWORD dwType; HKEY hKey; BOOL bRet = FALSE; RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\desktop"), 0, KEY_QUERY_VALUE, &hKey); if (!FAILED(RegQueryValueEx(hKey, _T("DragfullWindows"), NULL, &dwType, (LPBYTE)&sDragfullWindows, &cbDragfullWindows))) if (!_tcscmp(sDragfullWindows, _T("1"))) bRet = TRUE; RegCloseKey(hKey); return bRet; }